unit uAI.local;

interface

uses uDriver.local, uDefs.local, uRace.local, uTyres.local,

     Math;

type
  TAIBot = class( TObject )
  public
    constructor Create(DriverCount:integer);
    destructor Destroy; override;

    procedure Think_Fuel(var nDriver:TDriverItem;nTotalLaps,nLap:integer);
    function  Think_Tyres(var nDriver:TDriverItem;var nTyreList:TTyreList;nWeather:integer):integer;
    procedure Think_PitStopStints(var nDriver:TDriverItem;nRaceLaps:integer);
    procedure Think_PitStop(var nDriver:TDriverItem;nLap:integer);
    function  BotThink(var nDriver:TDriverItem;var nRace:TRace;var nTyreList:TTyreList):string;// BotBrain
  end;

implementation

uses uDebug.common;

constructor TAIBot.Create(DriverCount:integer);
begin
  inherited Create;

  DevConsole.Msg(ES_DEBUG, '[TAIBot.Create]');
end;
destructor TAIBot.Destroy;
begin

  inherited Destroy;
end;

procedure TAIBot.Think_Fuel(var nDriver:TDriverItem;nTotalLaps,nLap:integer);
begin
  with nDriver do
  begin
    if (FuelLaps <= 1) then
      Status := Status + [STATUS_PITTING];

    //====== Check Fuel Levels
    if (FuelLaps <= 0) then //Autopit for fuel
    begin
      Status := Status - [STATUS_PITTING] + [STATUS_PIT] + [STATUS_FUEL] + [STATUS_TYRES];

      if (FuelToFill < 0) then
        FuelToFill := ceil( nTotalLaps / FuelStints ); //number of projected pitstops

      if (FuelLaps + FuelToFill >= nTotalLaps) then // Autocatch a bad pitstop move
        FuelToFill := (nTotalLaps - nLap);

//      TyresToFit := Think_WhichTyres(nWeather); // Now handled in the Think_Tyres proc
    end;
  end;
end;
function TAIBot.Think_Tyres(var nDriver:TDriverItem;var nTyreList:TTyreList;nWeather:integer):integer; // This would be the AI phase.
var T, SuggestedTyres, TyreOpZone, CurrentGrip, TestGrip : integer;
begin
  with nDriver do
  begin // ERROR: The Code Below will not allow dry tyres other than Supersoft :(
    if (Tyres < 0) then // In no tyres selected, Fit the car with standard dry tyres.
      Tyres := 0;

    result         := -1; //No tyre change needed.
    SuggestedTyres := -1;

    TyreOpZone := nTyreList.TyreEffect(nTyreList.Items[ Tyres ].TOZ, nWeather) ;

    with nTyreList.Items[ Tyres ] do
      CurrentGrip := Round( DryGrip - (DryGrip * (TyreOpZone*0.01)));

//    if (CurrentGrip < 0) then CurrentGrip := 0
//    else if (CurrentGrip > 100) then CurrentGrip := 100;

    for T := 0 to High(nTyreList.Items) do
    begin
      TyreOpZone := nTyreList.TyreEffect(nTyreList.Items[T].TOZ, nWeather);
      with nTyreList.Items[ T ] do
        TestGrip := Round( DryGrip - (DryGrip * (TyreOpZone*0.01)));

      if (TestGrip > CurrentGrip) then // Higher is better, because its an actual "grip" in here.
      begin
        SuggestedTyres := T;
        CurrentGrip    := TestGrip;
      end;
    end;

    if (SuggestedTyres > -1) then
      result := SuggestedTyres;

//    if (TyreHealth <= 85)and( random(100) > TyreHealth ) then //Autopit for tyres
//      Status := Status - [STATUS_PITTING] + [STATUS_PIT] + [STATUS_TYRES];
  end;

end;
procedure TAIBot.Think_PitStopStints(var nDriver:TDriverItem;nRaceLaps:integer);
var Rand, StintLaps : integer;
begin
  with nDriver do
  begin
    rand := random(100);

    case rand of
      0..10   : begin
        SetLength(PitStops, 1);

        StintLaps := (Round(nRaceLaps/2)-3)+Random(6);

        PitStops[0] := TPitStop.Create();
        PitStops[0].SetPitStop(StintLaps, -1, -1);
      end;
      11..90  : begin
        SetLength(PitStops, 2);

//        StintLaps := (Round(nRaceLaps/3)-3)+Random(6);
        StintLaps := Round(nRaceLaps/3);

        PitStops[0] := TPitStop.Create();
        PitStops[0].SetPitStop((StintLaps-3)+Random(6), -1, -1);
        PitStops[1] := TPitStop.Create();
        PitStops[1].SetPitStop(((StintLaps*2)-3)+Random(6), -1, -1);
      end;
      else
      begin
        SetLength(PitStops, 3);

//        StintLaps := (Round(nRaceLaps/4)-3)+Random(6);
        StintLaps := Round(nRaceLaps/4);

        PitStops[0] := TPitStop.Create();
        PitStops[0].SetPitStop((StintLaps-3)+Random(6), -1, -1);
        PitStops[1] := TPitStop.Create();
        PitStops[1].SetPitStop(((StintLaps*2)-3)+Random(6), -1, -1);
        PitStops[2] := TPitStop.Create();
        PitStops[2].SetPitStop(((StintLaps*3)-3)+Random(6), -1, -1);
      end;
    end;
  end;
end;
procedure TAIBot.Think_PitStop(var nDriver:TDriverItem;nLap:integer);
var P : integer;
begin
  with nDriver do
  begin
    for P := 0 to High(PitStops) do
    begin
      if (PitStops[P].OnLap = nLap)and(not PitStops[P].Completed) then
      begin
        Status := Status - [STATUS_PITTING] + [STATUS_PIT] + [STATUS_TYRES];
//        TyresToFit := -1;
        PitStops[P].Completed := TRUE;
      end;
    end;
  end;
end;
function TAIBot.BotThink(var nDriver:TDriverItem;var nRace:TRace;var nTyreList:TTyreList):string; // This would be the AI phase.
begin
  result := '';

  Think_Fuel(nDriver,nRace.TotalLaps, nRace.Lap);

  if (nDriver.IsBot) then
  begin
    if (Random(100) > 30) then
      nDriver.TyresToFit := Think_Tyres(nDriver, nTyreList, nRace.Weather);

    Think_PitStop(nDriver, nRace.Lap);
  end;

  with nDriver do
  begin
    if (STATUS_CRASH in Status) then
      Status := Status + [STATUS_PIT] + [STATUS_TYRES];

    if (STATUS_PUNCTURE in Status) then
      Status := Status + [STATUS_PIT] + [STATUS_TYRES];
  end;
end;


end.
